import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2021-10-18')
}
export const navSortSelf = 5

{/* lint disable maximum-heading-length */}

<Note type="info">
  **Note**: Had trouble with something that wasn’t explained here but should be?
  Please let us know.
  See [§ Contribute][contribute] for how to help.
</Note>

# Troubleshooting MDX

This article goes through several common problems and errors that might occur
when using MDX. {/* more */}
To understand how the MDX format works, we recommend that you start with
[§ What is MDX][what].
How to use [our packages][packages] is documented in their readmes.
To migrate to the latest MDX, see [§ Migrating from v1 to v2][migation-v2].

## Contents

* [Problems integrating MDX](#problems-integrating-mdx)
  * [ESM](#esm)
* [Problems using MDX](#problems-using-mdx)
  * [`` `options.renderer` is no longer supported ``](#optionsrenderer-is-no-longer-supported)
  * [`` Incorrect `format: 'detect'` ``](#incorrect-format-detect)
  * [`` Unexpected `format: 'detect'` ``](#unexpected-format-detect)
  * [`` Missing `pragma` in classic runtime with `pragmaImportSource` ``](#missing-pragma-in-classic-runtime-with-pragmaimportsource)
  * [`` Unexpected deprecated option `jsxRuntime: 'classic'`, `pragma`, `pragmaFrag`, or `pragmaImportSource` ``](#unexpected-deprecated-option-jsxruntime-classic-pragma-pragmafrag-or-pragmaimportsource)
  * [`` Expected `Fragment` given to `evaluate` ``](#expected-fragment-given-to-evaluate)
  * [`` Expected `jsx` given to `evaluate` ``](#expected-jsx-given-to-evaluate)
  * [`` Expected `jsxs` given to `evaluate` ``](#expected-jsxs-given-to-evaluate)
  * [``Unexpected missing `options.baseUrl` needed…``](#unexpected-missing-optionsbaseurl-needed)
* [Problems writing MDX](#problems-writing-mdx)
  * [`Could not parse import/exports with acorn: $error`](#could-not-parse-importexports-with-acorn-error)
  * [``Unexpected `$type` in code: only import/exports are supported``](#unexpected-type-in-code-only-importexports-are-supported)
  * [`` Unexpected end of file in expression, expected a corresponding closing brace for `{` ``](#unexpected-end-of-file-in-expression-expected-a-corresponding-closing-brace-for-)
  * [`Unexpected lazy line in expression in container`](#unexpected-lazy-line-in-expression-in-container)
  * [`Could not parse expression with acorn: $error`](#could-not-parse-expression-with-acorn-error)
  * [`Could not parse expression with acorn: Unexpected content after expression`](#could-not-parse-expression-with-acorn-unexpected-content-after-expression)
  * [`Unexpected extra content in spread: only a single spread is supported`](#unexpected-extra-content-in-spread-only-a-single-spread-is-supported)
  * [``Unexpected `$type` in code: only spread elements are supported``](#unexpected-type-in-code-only-spread-elements-are-supported)
  * [`Unexpected empty expression`](#unexpected-empty-expression)
  * [`Unexpected end of file $at, expected $expect`](#unexpected-end-of-file-at-expected-expect)
  * [`Unexpected character $at, expected $expect`](#unexpected-character-at-expected-expect)
  * [``Unexpected closing slash `/` in tag, expected an open tag first``](#unexpected-closing-slash--in-tag-expected-an-open-tag-first)
  * [`Unexpected lazy line in container, expected line to be…`](#unexpected-lazy-line-in-container-expected-line-to-be)
  * [`Unexpected attribute in closing tag, expected the end of the tag`](#unexpected-attribute-in-closing-tag-expected-the-end-of-the-tag)
  * [``Unexpected self-closing slash `/` in closing tag, expected the end of the tag``](#unexpected-self-closing-slash--in-closing-tag-expected-the-end-of-the-tag)
  * [``Unexpected closing tag `</$tag>`, expected corresponding closing tag for `<$tag>` ($at)``](#unexpected-closing-tag-tag-expected-corresponding-closing-tag-for-tag-at)
  * [``Cannot close `$type` ($at): a different token (`$type`, $at) is open``](#cannot-close-type-at-a-different-token-type-at-is-open)
  * [``Cannot close document, a token (`$type`, $at) is still open``](#cannot-close-document-a-token-type-at-is-still-open)

## Problems integrating MDX

### ESM

If you’re having problems integrating MDX with different tools, that’s likely
due to ESM: ECMAScript modules.
They’ve been in the works since 2015, we’ve supported them in MDX files from the
start, and in MDX version 2 we completely switched to them.
Many tools support ESM already.
Most other tools are working hard to support them.
Some still require extra configuration.

There’s a great [Gist by
**@sindresorhus**](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c)
which explains in detail how to use ESM with many different tools.
If you’re having trouble with MDX, some other tool, and ESM,
you’ll likely find what you’re looking for there.
Please give it a thorough read.
If you’re still having problems, the issue tracker of the tools you’re
integrating MDX with might provide the answer.

If you’re having trouble with tools that don’t support ESM, such as Electron,
one short-term solution is to use a bundler to make a CJS version.

<details>
  <summary>Expand example of making a CJS bundle</summary>

  With [esbuild](https://esbuild.github.io), this bundles the ESM package
  `@mdx-js/mdx` as CJS in `vendor/mdx.js`:

  ```sh
  npx esbuild @mdx-js/mdx --bundle --platform=node --outfile=vendor/mdx.js
  ```
</details>

## Problems using MDX

Problems that occur when using MDX typically relate to the APIs of
[our packages][packages] and how to use them.
Please see the documentation of the packages, functions, and options you are
using for more info and examples.

### `` `options.renderer` is no longer supported ``

This error is thrown by [`@mdx-js/loader`][loader],
our webpack loader.
It was introduced in version 2 to help with migration.

The `renderer` option allowed arbitrary text to be injected before each compiled
MDX file.
This was typically used to support frameworks other than React such as Preact.
We now have options such as `jsxImportSource` for that and arbitrary JavaScript
can be added with `recmaPlugins`.
Because version 2 uses an AST based approach, it is no longer feasible to
support a `renderer`, so it was removed.

Please see [¶ Preact in § Getting started](/docs/getting-started/#preact) for
how to support Preact.
See [¶ Creating plugins in § Extending MDX](/docs/extending-mdx/#creating-plugins)
for how to create plugins.

### `` Incorrect `format: 'detect'` ``

### `` Unexpected `format: 'detect'` ``

The full error message in MDX 2 is as follows:

```mdx-invalid chrome=no
Incorrect `format: 'detect'`: `createProcessor` can support either `md` or `mdx`; it does not support detecting the format
```

The full error message in MDX 3 is:

```mdx-invalid chrome=no
Unexpected `format: 'detect'`, which is not supported by `createProcessor`, expected `'mdx'` or `'md'`
```

This error is thrown by [`@mdx-js/mdx`][mdx], our core compiler.
It was introduced in version 2 when the `format` option was introduced.

The `format` option, when configured with `'detect'`, allows inferring whether a
file is MDX or plain markdown.
Based on that information, plugins are configured differently, and with
different options.
This is impossible with `createProcessor` and `unified`.

To detect the format of passed files, please either use `compile` from
`@mdx-js/mdx` or one of the integrations.

### `` Missing `pragma` in classic runtime with `pragmaImportSource` ``

This error is thrown by [`@mdx-js/mdx`][mdx], our core compiler.
It was introduced in version 2 when the `jsxRuntime`, `pragma`, and
`pragmaImportSource` options were introduced.

This error is thrown when `jsxRuntime` is configured with `'classic'` (the
default is `'automatic'`), `pragmaImportSource` is defined (the default is
`'react'`), but `pragma` is defined as a falsey value (the default is
`React.createElement`).

If you are using the classic runtime, you have to define a `pragma`.

### `` Unexpected deprecated option `jsxRuntime: 'classic'`, `pragma`, `pragmaFrag`, or `pragmaImportSource` ``

This is a warning.
It is not an error.
You can keep on using these options, but expect them to be removed in the
future.

All major frameworks currently support the automatic JSX runtime.
The classic runtime, from MDX perspective, comes with several potential
problems.

Because of that, we strongly recommend using an automatic JSX runtime and are
considering removing support for the classic JSX runtime.

### `` Expected `Fragment` given to `evaluate` ``

### `` Expected `jsx` given to `evaluate` ``

### `` Expected `jsxs` given to `evaluate` ``

These errors are thrown by [`@mdx-js/mdx`][loader],
our core compiler.
They were introduced in version 2 when `evaluate` (and `evaluateSync`) were
introduced.

`evaluate` supports React and other frameworks.
But these frameworks must support an automatic JSX runtime that exposes these
three exports.
If you’re getting this error, that means that either a) the framework does not
support the automatic JSX runtime, or b) that you’re not passing them correctly
to `evaluate`.

Please see [`evaluate` in `@mdx-js/mdx`](/packages/mdx/#evaluatefile-options)
for examples on how to pass these values.

### ``Unexpected missing `options.baseUrl` needed…``

The full error message in MDX is as follows:

```mdx-invalid chrome=no
Unexpected missing `options.baseUrl` needed to support `export … from`, `import`, or `import.meta.url` when generating `function-body`
```

This error is thrown when MDX runs that is specifically compiled with
`evaluate`, or with the `outputFormat: 'function-body'` option to evluate
somewhere later, and `import.meta.url`, `import`, or `export … from` is used.
These JavaScript features depend on a particular URL to run from, which is not
available or not correct when running a function body.
To solve this, pass a `baseUrl` option.
Likely set to `import.meta.url` (or `window.location.href`).

## Problems writing MDX

Problems that occur when writing MDX typically have relate to how to combine
JS(X) and markdown.
It’s an odd mix of two languages: markdown is **whitespace sensitive** and
**forgiving** (what you type may not exactly work but it won’t crash) whereas
JavaScript is **whitespace insensitive** and **unforgiving** (it does crash on
typos).

Errors typically fall in these three categories:

* **Not escaping `<` and `{`**
  — Escape these (`\<`, `\{`) if you mean them as plain text instead of JS(X)
* **Incorrect interleaving**
  — See the rules in
  [¶ Interleaving in § What is MDX?][interleaving]
* **Broken JavaScript**
  — Make sure the JavaScript you write is valid

### `Could not parse import/exports with acorn: $error`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when the keywords `import` or `export` are found at the start of a
line but they are not followed by valid JavaScript.
An example is:

```mdx-invalid chrome=no
import 1/1
```

The reason for this error is that the parser is expecting a JavaScript import or
export statement.
If you want the word import or export, make sure it’s not at the start of a
paragraph.
If you do want an import or export statement, please make sure that it’s valid
JavaScript.

### ``Unexpected `$type` in code: only import/exports are supported``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when, after an `import` or `export` statement, more JavaScript is
found.
An example is:

```mdx-invalid chrome=no
export const a = 1
const b = 2
```

The reason for this error is that we only allow `import` and `export` to define
data.
If you want to define a variable or function, please export it.

### `` Unexpected end of file in expression, expected a corresponding closing brace for `{` ``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when there is an opening curly brace not followed by a closing brace.
An example is:

```mdx-invalid chrome=no
a { b
```

The reason for this error is that the parser is expecting another curly brace.
If you just want a brace but not an expression, escape it: `\{`.
If you do want an expression, please make sure to close it with a closing brace
`}`.
If there is a closing brace somewhere, make sure that the braces are each on
their own lines with no text before the opening brace and no text after the
closing brace, or that there are no blank lines between the braces.

### `Unexpected lazy line in expression in container`

This error is thrown by our MDX parser.
It was introduced in version 3.
It occurs when containers with lazy lines are combined with expressions
An example is:

```mdx-invalid chrome=no
* {1 +
2}

> {1 +
2}
```

The reason for this error is that the parser it likely points to a bug.
Be explicit with your list items and block quotes:

```mdx-invalid chrome=no
* {1 +
  2}

> {1 +
> 2}
```

### `Could not parse expression with acorn: $error`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when there are matching curly braces that, when interpreting what’s
inside them as JavaScript, results in a syntax error.
An example is:

```mdx-invalid chrome=no
a {const b = 'c'} d
```

Another example:

```mdx-invalid chrome=no
a {!} d
```

The reason for this error is that the parser is expecting a JavaScript
expression.
If you just want braces instead of an expression, escape the opening: `\{`.
If you do want an expression, make sure that it’s valid JavaScript and that it
is an expression.
That means statements (such as `if` and `else` and `for` loops) do not work.
If you need complex logic, you can wrap statements and whole programs into an
IIFE, or move it out to a different file, export it from there, and import it in
MDX.

### `Could not parse expression with acorn: Unexpected content after expression`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when there are matching curly braces that, and valid JavaScript is
inside them, but there’s too much JavaScript.
An example is:

```mdx-invalid chrome=no
a {'b' 'c'} d
```

The reason for this error is that the parser is expecting a single JavaScript
expression yielding one value.
If you just want braces instead of an expression, escape the opening: `\{`.
If you do want an expression, make sure that it yields a single value.

### `Unexpected extra content in spread: only a single spread is supported`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when there are multiple values spread into a JSX tag.
An example is:

```mdx-invalid chrome=no
<div {...a, ...b} />
```

The reason for this error is that JSX only allows spreading a single value at a
time:

```mdx chrome=no
<div {...a} {...b} />
```

### ``Unexpected `$type` in code: only spread elements are supported``

### `Unexpected empty expression`

These errors are thrown by our MDX parser.
They were introduced in version 2.
They occur when something other than a spread is used in braces.
An example is:

```mdx-invalid chrome=no
<div {values} {/* comment */} {} />
```

The reason for this error is that JSX only allows spreading values:

```mdx chrome=no
<div {...a} />
```

### `Unexpected end of file $at, expected $expect`

### `Unexpected character $at, expected $expect`

These errors are thrown by our MDX parser.
They were introduced in MDX version 2.
They occur when something unexpected was found in a JSX tag.
Some examples are:

```mdx-invalid chrome=no
<
<.>
</
</.>
<a
<a?>
<a:
<a:+>
<a.
<a./>
<a b
<a b!>
<a b:
<a b:1>
<a b=
<a b=>
<a b="
<a b='
<a b={
<a/
<a/->
```

The reason for these errors is that JSX has a very strict grammar and expects
tags to be valid.
There are different solutions depending on what was expected.
Please read the error message carefully as it indicates where the problem
occurred and what was expected instead.

### ``Unexpected closing slash `/` in tag, expected an open tag first``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when a closing tag is found but there are no open tags.
An example is:

```mdx-invalid chrome=no
</div>
```

The reason for this error is that only open tags can be closed.
You probably forgot an opening tag somewhere.

### `Unexpected lazy line in container, expected line to be…`

This error is thrown by our MDX parser.
It was introduced in version 3.
It occurs when containers with lazy lines are combined with JSX.
An example is:

```mdx-invalid chrome=no
* <x
y />

> <x
y />
```

The reason for this error is that the parser it likely points to a bug.
Be explicit with your list items and block quotes:

```mdx-invalid chrome=no
* <x
  y />

> <x
> y />
```

### `Unexpected attribute in closing tag, expected the end of the tag`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when attributes are placed on closing tags.
An example is:

```mdx-invalid chrome=no
<h1>Text</h1 id="text">
```

The reason for this error is that only open tags can have attributes.
Move these attributes to the corresponding opening tag.

### ``Unexpected self-closing slash `/` in closing tag, expected the end of the tag``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when a closing tag is also marked as self-closing.
An example is:

```mdx-invalid chrome=no
<h1>Text</h1/>
```

The reason for this error is that only opening tags can be marked as
self-closing.
Remove the slash after the tag name and before `>`.

### ``Unexpected closing tag `</$tag>`, expected corresponding closing tag for `<$tag>` ($at)``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when a closing tag is seen that does not match the expected opening
tag.
An example is:

```mdx-invalid chrome=no
<a>Text</b>
```

The reason for this error is that tags must match in JSX.
You likely forgot to open or close one of the two correctly.

### ``Cannot close `$type` ($at): a different token (`$type`, $at) is open``

### ``Cannot close document, a token (`$type`, $at) is still open``

This error is thrown by our MDX parser.
It was introduced in version 2.
It typically occurs when markdown and JSX are not interleaved correctly.
An example is:

```mdx-invalid chrome=no
> <div>
```

The reason for this error is that a markdown construct ends while there are
still tags open.
See the rules on
[¶ Interleaving in § What is MDX?][interleaving]

[contribute]: /community/contribute/

[interleaving]: /docs/what-is-mdx/#interleaving

[loader]: /packages/loader/

[mdx]: /packages/mdx/

[migation-v2]: /migrating/v2/

[packages]: /packages/

[what]: /docs/what-is-mdx/
